package com.example.mykotlin.controller

import cn.dev33.satoken.annotation.SaCheckPermission
import com.example.mykotlin.base.result.PageParam
import com.example.mykotlin.base.result.ServiceException
import com.example.mykotlin.base.util.Audit
import com.example.mykotlin.base.util.runService
import com.example.mykotlin.base.util.selectById
import com.example.mykotlin.base.util.tryOnly
import com.example.mykotlin.base.util.updateById
import com.example.mykotlin.base.valid.Insert
import com.example.mykotlin.base.valid.Update
import com.example.mykotlin.mapper.RolePermissionMapper
import com.example.mykotlin.mapper.UserRoleMapper
import com.example.mykotlin.model.dto.InsertRolePermissionsDTO
import com.example.mykotlin.model.dto.InsertRoleUsersDTO
import com.example.mykotlin.model.entity.ApiPermission
import com.example.mykotlin.model.entity.Role
import com.example.mykotlin.model.entity.RolePermission
import com.example.mykotlin.model.entity.User
import com.example.mykotlin.model.entity.UserRole
import com.example.mykotlin.model.enums.SystemRole
import com.example.mykotlin.service.AsyncEventService
import com.mybatisflex.kotlin.extensions.condition.allAnd
import com.mybatisflex.kotlin.extensions.db.deleteById
import com.mybatisflex.kotlin.extensions.db.deleteWith
import com.mybatisflex.kotlin.extensions.db.filter
import com.mybatisflex.kotlin.extensions.db.filterOne
import com.mybatisflex.kotlin.extensions.db.insert
import com.mybatisflex.kotlin.extensions.db.mapper
import com.mybatisflex.kotlin.extensions.db.paginate
import com.mybatisflex.kotlin.extensions.kproperty.eq
import com.mybatisflex.kotlin.extensions.kproperty.`in`
import com.mybatisflex.kotlin.extensions.wrapper.andAll
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.tags.Tag
import jakarta.validation.constraints.Size
import org.apache.commons.lang3.StringUtils
import org.springframework.validation.annotation.Validated
import org.springframework.web.bind.annotation.DeleteMapping
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.PutMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.RestController

@Tag(name = "角色表Controller", description = "相关接口")
@RestController
@Validated
@RequestMapping("/role")
class RoleController(
    private val asyncEventService: AsyncEventService,

    ) {
    @GetMapping
    @Operation(summary = "根据主键查询角色", description = "返回角色Role对象")
    @SaCheckPermission("GET_role")
    fun getRoleById(@RequestParam @Size(max = 64, message = "长度不能超过64") id: String) =
        runService { selectById<Role>(id) }

    @GetMapping("/inPage")
    @Operation(summary = "分页条件查询角色", description = "返回角色Role对象列表")
    @SaCheckPermission("GET_role_inPage")
    fun getRoleInPage(role: Role, @Validated p: PageParam) = runService {
        paginate<Role>(p.page()) {
            andAll(
                (Role::id eq role.id).`when`(StringUtils.isNotEmpty(role.id)),
                (Role::name eq role.name).`when`(StringUtils.isNotEmpty(role.name)),
                (Role::description eq role.description).`when`(StringUtils.isNotEmpty(role.description)),
            )
        }
    }

    @PostMapping
    @Operation(summary = "新增角色", description = "返回新增的角色Role对象")
    @SaCheckPermission("POST_role")
    @Audit
    fun insertRole(@RequestBody @Validated(Insert::class) role: Role) = runService {
        insert(role)
        role
    }


    @PostMapping("/permission")
    @Operation(summary = "角色绑定多个权限", description = "角色绑定多个权限")
    @SaCheckPermission("POST_role_permission")
    @Audit
    fun insertRolePermissions(@RequestBody rolePermissions: InsertRolePermissionsDTO) = runService {
        if (rolePermissions.roleId == SystemRole.SUPER_ADMIN.name)
            return@runService true
        filterOne<Role>(Role::id) { Role::id eq rolePermissions.roleId }
            ?: throw ServiceException("[roleId=${rolePermissions.roleId}]数据不存在")
        if (!rolePermissions.addPermissionList.isNullOrEmpty()) {
            val addPermissionList = filter<ApiPermission>(ApiPermission::id) {
                ApiPermission::id `in` rolePermissions.addPermissionList!!
            }
            if (addPermissionList.isNotEmpty()) {
                val permissionList = addPermissionList.map { it.id ?: "" }
                val selectList = filter<RolePermission> {
                    allAnd(
                        RolePermission::roleId eq rolePermissions.roleId,
                        RolePermission::permissionId `in` permissionList
                    )
                }
                if (selectList.isEmpty()) {
                    tryOnly {
                        mapper<RolePermissionMapper>().insertBatch(permissionList.map {
                            RolePermission(
                                rolePermissions.roleId, it
                            )
                        })
                    }
                } else if (selectList.size < permissionList.size) {
                    val minus = permissionList.minus(selectList.map { it.permissionId }.toSet())
                    tryOnly {
                        mapper<RolePermissionMapper>().insertBatch(minus.map {
                            RolePermission(
                                rolePermissions.roleId,
                                it
                            )
                        })
                    }
                }
            }
        }
        if (!rolePermissions.removePermissionList.isNullOrEmpty()) {
            tryOnly {
                deleteWith<RolePermission> {
                    allAnd(
                        RolePermission::roleId eq rolePermissions.roleId,
                        RolePermission::permissionId `in` rolePermissions.removePermissionList!!
                    )
                }
            }
        }
        return@runService true
    }

    @PutMapping
    @Operation(summary = "根据主键修改角色", description = "返回修改后的角色Role对象")
    @SaCheckPermission("PUT_role")
    @Audit
    fun updateRole(@RequestBody @Validated(Update::class) role: Role) = runService {
        val byId = selectById<Role>(role.id!!) ?: throw ServiceException("[id=${role.id}]数据不存在")
        updateById(role)
        if (role.id != null) byId.id = role.id
        if (StringUtils.isNotEmpty(role.name)) byId.name = role.name
        if (StringUtils.isNotEmpty(role.description)) byId.description = role.description
        if (role.createTime != null) byId.createTime = role.createTime
        if (role.updateTime != null) byId.updateTime = role.updateTime
        byId
    }

    @DeleteMapping
    @Operation(summary = "根据主键删除角色", description = "返回被删除的角色Role对象")
    @SaCheckPermission("DELETE_role")
    @Audit
    fun deleteRoleById(@RequestParam @Size(max = 64, message = "长度不能超过64") id: String) = runService {
        try {
            SystemRole.valueOf(id)
            throw ServiceException("[$id]为系统角色,不支持删除")
        } catch (_: IllegalArgumentException) {
        }
        val byId = selectById<Role>(id) ?: throw ServiceException("[id=${id}]数据不存在")
        if (deleteById<Role>(id) > 0) {
            asyncEventService.deleteRoleEvent(id)
            byId
        } else throw ServiceException("[id=${id}]数据删除失败")
    }

    @PostMapping("/user")
    @Operation(summary = "给角色添加多个用户", description = "给角色添加多个用户")
    @SaCheckPermission("POST_role_user")
    @Audit
    fun insertRoleUsers(@RequestBody roleUsers: InsertRoleUsersDTO) = runService {
        if (roleUsers.roleId == SystemRole.USER.name)
            return@runService true
        filterOne<Role>(Role::id) { Role::id eq roleUsers.roleId }
            ?: throw ServiceException("角色[${roleUsers.roleId}]不存在")
        if (!roleUsers.addUserList.isNullOrEmpty()) {
            val addUserList = filter<User>(User::id) { User::id `in` roleUsers.addUserList!! }
            if (addUserList.isNotEmpty()) {
                val userList = addUserList.map { it.id ?: 0 }
                val inDbList = filter<UserRole> {
                    allAnd(
                        UserRole::roleId eq roleUsers.roleId,
                        UserRole::userId `in` userList
                    )
                }
                if (inDbList.isEmpty()) {
                    tryOnly {
                        mapper<UserRoleMapper>().insertBatch(userList.map {
                            UserRole(
                                it, roleUsers.roleId
                            )
                        })
                    }
                } else if (inDbList.size < userList.size) {
                    val minus = userList.minus(inDbList.map { it.userId }.toSet())
                    tryOnly {
                        mapper<UserRoleMapper>().insertBatch(minus.map { UserRole(it, roleUsers.roleId) })
                    }
                }
            }
        }
        if (!roleUsers.removeUserList.isNullOrEmpty()) {
            tryOnly {
                deleteWith<UserRole> {
                    allAnd(
                        UserRole::roleId eq roleUsers.roleId,
                        UserRole::userId `in` roleUsers.removeUserList!!
                    )
                }
            }
        }
        return@runService true
    }

}